package xj.graph2d.template;

import java.util.Map;

import xj.graph2d.ArrowAttr;
import xj.graph2d.CompoundDrawShape;
import xj.graph2d.DrawAttr;
import xj.graph2d.DrawShape;
import xj.graph2d.DrawShapeConstants;
import xj.graph2d.EllipseShape;
import xj.graph2d.GraphEdgeBase;
import xj.graph2d.GraphNodeBase;
import xj.graph2d.Group;
import xj.graph2d.LineShape;
import xj.graph2d.RectangleShape;
import xj.graph2d.TextShape;
import xj.graph2d.shapes.OrthogonalSelfLoop;
import xj.graph2d.shapes.ShapeConstants;
import xj.graph2d.shapes.uml.LifeLineShape;
import xj.graph2d.template.uml.UMLExecutionOccuranceModelListener;
import xj.graph2d.template.uml.UMLLifeLineModelListener;
import xj.graph2d.template.uml.UMLMessageModelListener;
import xj.graph2d.template.uml.UMLObjectModelListener;
import xj.model.uml.ExecutionOccurance;
import xj.model.uml.LifeLine;
import xj.model.uml.SequenceNode;
import xj.model.uml.UMLMessage;
import xj.model.uml.UMLObject;

public class UMLSequenceDiagramTemplate extends UMLTemplate {

  // Sequence Diagram

  static String[][] sequenceDiagramGapToolNames = {
    { "Receive", "Send", "Stop", },
    { "Object", "LifeLine2", }      
  };

  public UMLSequenceDiagramTemplate() {
  }

  @Override
  public String[][] getGapToolNames() { 
    return sequenceDiagramGapToolNames;
  }

  @Override
  public void makeTemplate(Map iconMap) {
    addObjectTemplate("Object", 0, 0, 100, 30);

    addLifeLineTemplate("LifeLine", 50, 0, 100);

    // compound template
    LineShape line = new LineShape(50, 30, 50, 100);
    addLifeLineObjectTemplate("LifeLine2", 0, 0, 100, 30);

    addExecutionOccuranceTemplate("Execution", 0, 0, 10, 100);

    addNodeTemplate("Stop", SequenceNode.SequenceNodeType.Terminate, 
		    0, 0, 15, 15);

    addNodeTemplate("Receive", SequenceNode.SequenceNodeType.Receive_Message,
		    10, 10, 15, 15);
    addNodeTemplate("Send", SequenceNode.SequenceNodeType.Send_Message, 
		    10, 10, 15, 15);

    line = new LineShape(0, 20, 50, 20);
    line.setHorizontal(true);
    addMessageTemplate("Message1", UMLMessage.MessageType.Asynchorous_Call, line);

    line = new LineShape(0, 20, 50, 20);
    line.setHorizontal(true);
    addMessageTemplate("Message2", UMLMessage.MessageType.Synchorous_Call, line);


    //OrthogonalLineShape oline = new OrthogonalLineShape(false, 0, 0);
    //oline.addPoint(50, 50);
    //oline.addPoint(0, 100);

    OrthogonalSelfLoop oline = new OrthogonalSelfLoop(0, 0, 0, 60, 30,
						      ShapeConstants.EAST);
    oline.calculateBounds();
    addMessageTemplate("Message7", UMLMessage.MessageType.Synchorous_Call, oline);

    // line = new LineShape(0, 20, 50, 20);
    line = new LineShape(50, 20, 0, 20);
    line.setHorizontal(true);
    addMessageTemplate("Message3", UMLMessage.MessageType.Return, line);

    line = new LineShape(0, 20, 50, 40);
    line.setHorizontal(false);
    addMessageTemplate("Message4", UMLMessage.MessageType.Asynchorous_Call,
		       line);

    line = new LineShape(0, 20, 50, 40);
    line.setHorizontal(false);
    addMessageTemplate("Message5", UMLMessage.MessageType.Synchorous_Call, line);

    // line = new LineShape(0, 20, 50, 40);
    line = new LineShape(50, 20, 0, 40);
    line.setHorizontal(false);
    addMessageTemplate("Message6", UMLMessage.MessageType.Return, line);

    // notes
    addNotesTemplate("Notes1", true, "Link");
    addNotesTemplate("Notes2", false);

    // link
    addNotesLinkTemplate("Link", new LineShape(0, 20, 50, 20));
  }

  protected void addObjectTemplate(String tempName, 
				   float x, float y, float w, float h) {
    int iconWidth = 36, iconHeight = 30;
    DrawShape iconShape = new RectangleShape(x, y, x + w, y + h);
    setNodeAttr(iconShape);
    setNodeColor(iconShape, OBJECT_FG, OBJECT_BG);

    RectangleShape shape = new RectangleShape(x, y, x + w, y + h);
    setNodeAttr(shape);
    setNodeColor(shape, OBJECT_FG, OBJECT_BG);
    TextShape text = makeTitleText("object : Class", OBJECT_FONT, OBJECT_COLOR);
    text.setDisplayName("Name");
    shape.setLabel(DrawShapeConstants.ROLE_NODE_LABEL, text);
    shape.setAcceptSubshape(false);
    shape.setScaleMode(DrawShapeConstants.SCALE_EXCLUDE_SUBSHAPE);

    shape.setModel(new UMLObject());
    shape.setModelListener(new UMLObjectModelListener());

    add(new TemplateToolButton(tempName, shape, iconShape, iconWidth, iconHeight, 
			       false, true));
  }

  protected void addLifeLineTemplate(String tempName, float x, float y1, float y2) {
    int iconWidth = 36, iconHeight = 30;
    LifeLineShape shape = new LifeLineShape(x, y1, y2);
    setLineAttr(shape, DrawAttr.DASHED_LINE, null, 0, null, 0);
    setPenColor(shape, LIFELINE_COLOR);

    shape.setModel(new LifeLine());
    shape.setModelListener(new UMLLifeLineModelListener());
    add(new TemplateToolButton(tempName, shape, iconWidth, iconHeight, false, true));
  }

  protected void addLifeLineObjectTemplate(String tempName, 
					   float x, float y, float w, float h) {
    int iconWidth = 36, iconHeight = 30;

    // object
    RectangleShape rect = new RectangleShape(x, y, x + w, y + h);
    rect.setDisplayName("Object");
    rect.initComponent();
    setNodeAttr(rect);
    setNodeColor(rect, OBJECT_FG, OBJECT_BG);
    TextShape text = makeTitleText("object : Class", OBJECT_FONT, OBJECT_COLOR);
    text.setDisplayName("Name");
    rect.setLabel(DrawShapeConstants.ROLE_NODE_LABEL, text);
    rect.setAcceptSubshape(false);
    rect.setScaleMode(DrawShapeConstants.SCALE_EXCLUDE_SUBSHAPE);

    rect.setModel(new UMLObject());
    rect.setModelListener(new UMLObjectModelListener());

    // lifeline
    LifeLineShape line = new LifeLineShape(x + w / 2, y + h, y + 3 * h);
    line.setDisplayName("Life Line");
    line.setTemplateName("LifeLine");
    setLineAttr(line, DrawAttr.DASHED_LINE, null, 0, null, 0);
    setPenColor(line, LIFELINE_COLOR);
    line.initComponent();

    line.setModel(new LifeLine());
    line.setModelListener(new UMLLifeLineModelListener());

    // group
    Group shape = new Group(true); // temporary
    shape.addShape(rect);
    shape.addShape(line);

    // icon
    DrawShape iconRect = new RectangleShape(x, y, x + w, y + h);
    setNodeAttr(iconRect);
    setNodeColor(iconRect, OBJECT_FG, OBJECT_BG);
    LineShape iconLine = new LineShape(x + w / 2, y + h, x + w / 2, y + 3 * h);
    setLineAttr(iconLine, DrawAttr.DASHED_LINE, null, 0, null, 0);
    setPenColor(iconLine, LIFELINE_COLOR);
    Group iconShape = new Group();
    iconShape.addShape(iconRect);
    iconShape.addShape(iconLine);
    iconShape.fitComponents();

    add(new TemplateToolButton(tempName, shape, iconShape, iconWidth, iconHeight, false,
	true));
  }

  protected void addExecutionOccuranceTemplate(String tempName, 
					       float x, float y, float w, float h) {
    RectangleShape shape = new RectangleShape(x, y, x + w, y + h, true);
    shape.setFixedWidth(true);
    shape.setAcceptSubshape(true);
    shape.setOnBoundary(true);
    shape.setBoundaryPosition(GraphNodeBase.BOUNDARY_POSITION_EAST);

    int iconWidth = 36, iconHeight = 30;
    if (shape != null) {
      setNodeAttr(shape);
      setNodeColor(shape, EXECUTION_FG, EXECUTION_BG, false);

      shape.setModel(new ExecutionOccurance());
      shape.setModelListener(new UMLExecutionOccuranceModelListener());
      add(new TemplateToolButton(tempName, shape, iconWidth, iconHeight, false, true));
    }
  }

  protected void addMessageTemplate(String tempName,
				    UMLMessage.MessageType type, GraphEdgeBase shape) {
    int iconWidth = 36, iconHeight = 30;
    if (shape != null) {
      switch (type) {
      case Synchorous_Call:
	setLineAttr(shape, DrawAttr.SOLID_LINE,
		    ArrowAttr.ArrowType.FilledTriangle, 12, null, 0);
	setPenColor(shape, SYNC_MESSAGE_COLOR);
	break;
      case Asynchorous_Call:
	setLineAttr(shape, DrawAttr.SOLID_LINE, ArrowAttr.ArrowType.LineArrow,
		    12, null, 0);
	setPenColor(shape, ASYNC_MESSAGE_COLOR);
	break;
      case Return:
	setLineAttr(shape, DrawAttr.DOTTED_LINE, ArrowAttr.ArrowType.LineArrow,
		    12, null, 0);
	setPenColor(shape, RETURN_MESSAGE_COLOR);
	break;
      case Lost_Massge:
      case Found_Massge:
      case Create_Object:
      case Delete_Object:
      default:
	setLineAttr(shape, DrawAttr.SOLID_LINE, ArrowAttr.ArrowType.LineArrow,
		    12, null, 0);
      }

      shape.setModel(new UMLMessage(type));
      shape.setModelListener(new UMLMessageModelListener(this));
      add(new TemplateToolButton(tempName, shape, iconWidth, iconHeight, false, true));
    }
  }

  protected void addNodeTemplate(String tempName,
				 SequenceNode.SequenceNodeType type, 
				 float x, float y, float w, float h) {
    int iconWidth = 36, iconHeight = 16;
    DrawShape shape = null;
    DrawShape iconShape = null;
    switch (type) {
    case Receive_Message:
    case Send_Message:
      shape = new EllipseShape(x, y, x + w, y + h, true);
      shape.showBorder(false);
      shape.setFixedRatio(true);
      shape.setAtomic(true);
      shape.setResizable(false);
      shape = setNodeAttr(shape);
      if (type == SequenceNode.SequenceNodeType.Receive_Message) {
	setNodeBgColor(shape, RECEIVE_BG, true);
      } else {
	setNodeBgColor(shape, SEND_BG, true);
      }
      break;

    case Terminate:
      shape = new RectangleShape(x, y, x + w, y + h);
      shape.setFixedRatio(true);
      shape.setAllowRotation(false);
      shape.setAtomic(true);
      shape.setResizable(false);
      shape.showBorder(false);
      DrawShape s1 = new LineShape(x, y, x + w, y + h);
      shape.addShape(setLineWidth(s1, 2));
      setPenColor(s1, STOP_BG);
      s1 = new LineShape(x, y + h, x + w, y);
      shape.addShape(setLineWidth(s1, 2));
      setPenColor(s1, STOP_BG);

      // icon
      CompoundDrawShape comp = new CompoundDrawShape();
      comp.setName(tempName);
      comp.setAtomic(true);
      s1 = new LineShape(x, y, x + w, y + h);
      comp.addShape(setLineWidth(s1, 2));
      setPenColor(s1, STOP_BG);
      s1 = new LineShape(x, y + h, x + w, y);
      comp.addShape(setLineWidth(s1, 2));
      setPenColor(s1, STOP_BG);
      comp.fitComponents();
      iconShape = comp;
      break;
    }

    if (shape != null) {
      shape.setModel(new SequenceNode(type));
      // shape.setModelListener(new UMLSequenceNodeModelListener());
      add(new TemplateToolButton(tempName, shape, iconShape, iconWidth, iconHeight, false, true));
    }
  }

  public static final String FRAME_BG = "template.UMLSequenceDiagram.Frame.bg";

  public static final String OBJECT_BG = "template.UMLSequenceDiagram.Object.bg";

  public static final String OBJECT_FG = "template.UMLSequenceDiagram.Object.fg";

  public static final String OBJECT_FONT = "template.UMLSequenceDiagram.Object.font";

  public static final String OBJECT_COLOR = "template.UMLSequenceDiagram.Object.color";

  public static final String LIFELINE_COLOR = "template.UMLSequenceDiagram.LifeLine.color";

  public static final String EXECUTION_BG = "template.UMLSequenceDiagram.Execution.bg";

  public static final String EXECUTION_FG = "template.UMLSequenceDiagram.Execution.fg";

  public static final String MESSAGE_FONT = "template.UMLSequenceDiagram.Message.font";

  public static final String MESSAGE_COLOR = "template.UMLSequenceDiagram.Message.color";

  public static final String SYNC_MESSAGE_COLOR = "template.UMLSequenceDiagram.SyncMessage.color";

  public static final String ASYNC_MESSAGE_COLOR = "template.UMLSequenceDiagram.AsyncMessage.color";

  public static final String RETURN_MESSAGE_COLOR = "template.UMLSequenceDiagram.ReturnMessage.color";

  public static final String STOP_BG = "template.UMLSequenceDiagram.Stop.bg";

  public static final String RECEIVE_BG = "template.UMLSequenceDiagram.Receive.bg";

  public static final String SEND_BG = "template.UMLSequenceDiagram.Send.bg";

}
